/**
 * Main Class for searching data
 */
package search;

import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import au.com.bytecode.opencsv.*;

/**
 * @author Feenics, Ricky, Vic
 * @start_date 2012/04/03
 */
public class Search {

	static String TRANSFER_CONFIG_CSV = "data/TransferConfig/TransferConfiguration.csv";
	static String FileName_CSV = "data/TransferConfig/FileName.csv";

	static String TRANSFER_TO = "\tTransfer from here to";
	static String DEP = "DEP";
	static String ARR = "ARR";
	static String ROUTE = "Route ";
	static String FROM = "FROM: ";
	static String TO = "TO: ";
	static String COLON = ":";
	static String SEPARATE_LINE = "============================";
	static String STR_MONDAY = "Monday";
	static String STR_TUESDAY = "Tuesday";
	static String STR_WEDNESDAY = "Wednesday";
	static String STR_THURSDAY = "Thursday";
	static String STR_FRIDAY = "Friday";
	static String STR_SATURDAY = "Saturday";
	static String STR_SUNDAY = "Sunday";
	static String SimpleDateFormat = "hh:mm:ss";

	static int NORMAL = 0;
	static int ERR_NO_RESULT_FOUND = -3;
	static int ERR_CSV_FILE_FORMAT = -4;
	static int ERR_FATAL = -99;

	static String ERR_FATAL_MESSAGE = "E-99 FATAL ERROR!";

	int searchResultNumber = 0;

	/**
	 * Main Search Method
	 * 
	 * @author Ricky
	 * @start_date 2012/04/03
	 */
	private ArrayList<String> searchResult = new ArrayList<String>();
	private String dow;

	public ArrayList<String> doSearch(String departService, String departLine,
			String departStation, String arriveService, String arriveLine,
			String arriveStation, String departingDay,
			String departingMonthYear, String departingHour,
			String departingMinute) {

		String[] params = new String[10];

		params[0] = departService.trim();
		params[1] = departLine.trim();
		params[2] = departStation.trim();
		params[3] = arriveService.trim();
		params[4] = arriveLine.trim();
		params[5] = arriveStation.trim();
		params[6] = departingDay.trim();
		params[7] = departingMonthYear.trim();
		params[8] = departingHour.trim();
		params[9] = departingMinute.trim();

		// //check for Date
		// if (checkDate(params) == false) {
		// searchResult[0] =
		// "invalid input of Day, Please enter a correct Day.";
		// return searchResult;
		// }

		dow = getDayOfWeek(params[6], params[7]);

		searchResult.add(FROM + params[2]);
		searchResult.add(TO + params[5]);
		searchResult.add(SEPARATE_LINE);

		if (params[0].equals(params[3]) && params[1].equals(params[4])) {
			doSingleSearch(params);

		} else {
			doMultipleSearchMain(params);
		}

		return searchResult;

	}

	/**
	 * Search Method for single route
	 * 
	 * @author Vic
	 * @start_date 2012/04/03
	 */
	private int doSingleSearch(String[] params) {

		// Check the section by "["
		boolean hasRead = false;
		// Found the proper time
		boolean found = false;
		// Loop valuable
		int i = 0;
		int j = 0;
		int k = 0;
		int fileSelectorNumber = 0;

		String[] nextLine;
		String[] nextLine1;

		// Temporary time valuable
		Date tempT;
		DateFormat sdf;
		String tempTime;

		Date resultDepartingTime = null;
		Date resultArriveTime = null;
		// One whole line of the right departline
		String[] departLine = null;
		// One whole line of the right arriveline
		String[] arriveLine = null;
		// The whole name of the cvs file
		String[] fileSelector = new String[2];
		String[] fileNameAnalysis;
		String direction = null;

		try {
			// Convert to time (hour + min)
			tempTime = params[8] + COLON + params[9] + COLON + "00";

			// Format the time object
			sdf = new SimpleDateFormat(SimpleDateFormat);

			resultDepartingTime = sdf.parse(tempTime);
			CSVReader reader = new CSVReader(new FileReader(FileName_CSV));

			while ((nextLine = reader.readNext()) != null) {
				if (nextLine[0].toLowerCase().contains(params[0].toLowerCase())
						&& nextLine[0].toLowerCase().contains(params[1].toLowerCase())) {
					fileSelector[fileSelectorNumber++] = nextLine[0];
				}
			}

			for (i = 0; i < fileSelector.length; i++) {

				CSVReader reader1 = new CSVReader(new FileReader(
						fileSelector[i]));
				
				fileNameAnalysis = fileSelector[i].split("-");
				if(fileNameAnalysis == null || fileNameAnalysis.length != 2){
					return ERR_CSV_FILE_FORMAT;
				}
				direction = fileNameAnalysis[1].trim().replace("_", " ").replace(".csv", "");
				
				hasRead = false;

				while ((nextLine1 = reader1.readNext()) != null) {

					if (nextLine1 == null
							|| (hasRead == true && nextLine1[0].startsWith("["))) {
						break;
					}

					if(nextLine1[0].startsWith("[")){
						for (j = 0; j < nextLine1.length; j++) {
							if (nextLine1[j].contains(dow)) {
								hasRead = true;
							}
						}
					}
	
					if (hasRead == true) {
						if (nextLine1[0].toLowerCase().contains(params[2].toLowerCase())
								&& departLine == null) {
							departLine = nextLine1;
							if(departLine[0].contains(ARR)){
								departLine = null;
								continue;
							}
							if(departLine[0].contains(DEP)){
								departLine[0] = departLine[0].replace(DEP, "").trim();
							}
						}
						if (nextLine1[0].toLowerCase().contains(params[5].toLowerCase())
								&& departLine != null) {
							arriveLine = nextLine1;
						}
					}
					
					if(departLine != null && arriveLine != null){
						break;
					}
				}

				if (departLine != null && arriveLine != null) {
					break;
				} else {
					departLine = null;
					arriveLine = null;
				}
			}

			if (departLine != null && arriveLine != null) {
				for (k = 1; k < departLine.length; k++) {
					try {
						tempT = sdf.parse(departLine[k] + COLON + "59");
					} catch (Exception e) {
						//e.printStackTrace();
						continue;
					}
					if (tempT.after(resultDepartingTime)) {
						resultDepartingTime = tempT;
						try {
							resultArriveTime = sdf.parse(arriveLine[k] + COLON + "59");
							found = true;
							break;
						} catch (ParseException e) {
							//e.printStackTrace();
							continue;
						}
					}
				}
			}
			if (found == true && departLine != null && arriveLine != null) {
				searchResult.add("DEP: "
						+ departLine[k] + " From " + departLine[0]);
				searchResult.add("Take the " + params[0] + " " + params[1] 
						+ " towards " + direction);
				searchResult.add("ARR: " + arriveLine[k]
						+ " Get off at " + arriveLine[0]);

			} else {
				searchResult.add("E-03 No result found.");
			}

		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL;
		}

		return NORMAL;
	}

	/**
	 * Search Method for multiple route
	 * 
	 * @author Feenics
	 * @start_date 2012/04/03
	 */
	private int doMultipleSearchMain(String[] params) {

		int getRoutesResult;

		String[][] routes = new String[10][2];
		String[] getRoutesParams = new String[4];

		getRoutesParams[0] = params[0];
		getRoutesParams[1] = params[1];
		getRoutesParams[2] = params[3];
		getRoutesParams[3] = params[4];

		getRoutesResult = getRoutes(getRoutesParams, routes);

		if (getRoutesResult == NORMAL) {
			doMultipleSearch(params, routes);
		} else {
			return getRoutesResult;
		}

		return NORMAL;
	}
	
	/**
	 * Search Method for multiple route
	 * 
	 * @author Feenics
	 * @start_date 2012/04/03
	 */
	private int doMultipleSearch(String[] params, String[][] routes) {

		int singleSearchResult = NORMAL;

		String[] doSingleSearchParams = params.clone();

		String[] transferStationInformation1;
		String[] transferStationInformation2;
		String[] transferTime;

		if (routes != null) {
			for (int i = 0; i < routes.length; i++) {
				if(routes[i] == null || routes[i][0] == null){
					break;
				}
				
				searchResult.add(ROUTE
						+ String.valueOf(i + 1) + COLON);

				transferStationInformation1 = routes[i][0].split("-");
				transferStationInformation2 = routes[i][1].split("-");

				if (transferStationInformation1.length != 3
						|| transferStationInformation2.length != 3) {
					return ERR_CSV_FILE_FORMAT;
				}

				doSingleSearchParams[3] = transferStationInformation1[0].trim(); // arriveService
				doSingleSearchParams[4] = transferStationInformation1[1].trim(); // arriveLine
				doSingleSearchParams[5] = transferStationInformation1[2].trim(); // arriveStation

				singleSearchResult = doSingleSearch(doSingleSearchParams);
				if (singleSearchResult != NORMAL) {
					return singleSearchResult;
				}

				doSingleSearchParams[0] = transferStationInformation2[0].trim(); // departService
				doSingleSearchParams[1] = transferStationInformation2[1].trim(); // departLine
				doSingleSearchParams[2] = transferStationInformation2[2].trim(); // departStation
				doSingleSearchParams[3] = params[3].trim(); // arriveService
				doSingleSearchParams[4] = params[4].trim(); // arriveLine
				doSingleSearchParams[5] = params[5].trim(); // arriveStation

				transferTime = searchResult.get(searchResult.size()-1).substring(4, 
						searchResult.get(searchResult.size()-1).indexOf("Get off at")).split(":");
				if (transferTime.length != 2) {
					return ERR_FATAL;
				}

				doSingleSearchParams[8] = transferTime[0].trim(); // arriveStation
				doSingleSearchParams[9] = transferTime[1].trim(); // arriveStation

				searchResult.add(TRANSFER_TO);
				singleSearchResult = doSingleSearch(doSingleSearchParams);
				if (singleSearchResult != NORMAL) {
					return singleSearchResult;
				}

				searchResult.add(SEPARATE_LINE);
			}
		} else {
			return ERR_FATAL;
		}

		return NORMAL;
	}

	/**
	 * Get day of week
	 * 
	 * @author Feenics
	 * @start_date 2012/04/04
	 */
	private String getDayOfWeek(String day, String monthYear) {
		String dow = null;
		int intDow;

		try {
			SimpleDateFormat dft = new SimpleDateFormat("dd/mm/yyyy");
			Date date = dft.parse(day + "/" + monthYear);
			Calendar calendar = Calendar.getInstance();

			calendar.setTime(date);
			intDow = calendar.get(Calendar.DAY_OF_WEEK);

			switch (intDow) {
			case Calendar.MONDAY:
				dow = STR_MONDAY;
				break;
			case Calendar.TUESDAY:
				dow = STR_TUESDAY;
				break;
			case Calendar.WEDNESDAY:
				dow = STR_WEDNESDAY;
				break;
			case Calendar.THURSDAY:
				dow = STR_THURSDAY;
				break;
			case Calendar.FRIDAY:
				dow = STR_FRIDAY;
				break;
			case Calendar.SATURDAY:
				dow = STR_SATURDAY;
				break;
			case Calendar.SUNDAY:
				dow = STR_SUNDAY;
				break;
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL_MESSAGE;
		}

		return dow;
	}

	/**
	 * Get routes
	 * 
	 * @author Feenics
	 * @start_date 2012/04/03
	 */
	private int getRoutes(String[] params, String[][] routes) {
		try {
			String departServiceLine = params[0] + "-" + params[1];
			String arriveServiceLine = params[2] + "-" + params[3];

			int routesLine = 0;

			CSVReader reader = new CSVReader(
					new FileReader(TRANSFER_CONFIG_CSV));
			String[] nextLine;

			while ((nextLine = reader.readNext()) != null) {
				for (int i = 0; i < nextLine.length; i++) {
					if (nextLine[i].contains(departServiceLine)) {
						routes[routesLine][0] = nextLine[i];
					}
					if (nextLine[i].contains(arriveServiceLine)) {
						routes[routesLine][1] = nextLine[i];
					}
				}
				if (routes[routesLine][0] == null
						|| routes[routesLine][1] == null) {
					routes[routesLine][0] = null;
					routes[routesLine][1] = null;
				} else {
					routesLine++;
				}
			}

			if (routesLine == 0) {
				return ERR_NO_RESULT_FOUND;
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERR_FATAL;
		}
		return NORMAL;
	}
}
